﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;

using System.Diagnostics;
using System.Drawing;

using System.Threading;
using System.Threading.Tasks;

using Styx;
using Styx.Common;
using Styx.Common.Helpers;

using Styx.CommonBot;
using Styx.CommonBot.POI;
using Styx.CommonBot.Routines;
using Styx.CommonBot.Coroutines;

using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.DBC;
using Styx.WoWInternals.WoWObjects;

using CommonBehaviors.Actions;
using Action = Styx.TreeSharp.Action;

using KittyDru.Helpers;
using KittyDru.Rotation;


/*
 * TODO:
 * 1) не вызывать PreCombatBuffs повторно
 */

namespace KittyDru
{
    class KittyDru : CombatRoutine
    {
        #region Singleton Instance
        public static KittyDru Instance { get; private set; }
        public KittyDru() { 
            Instance = this;
            timer.Start();
        }
        #endregion

        #region Name && Class
        public override sealed string Name { get { return "KittyDru - Feral Class " + Version.ToString(); } }
        public override WoWClass Class { get { return WoWClass.Druid; } }
        public Version Version { get { return new Version(1, 0, 0, 2); } }
        #endregion

        #region GUI Call
        public override bool WantButton { get { return true; } }
        public override void OnButtonPress() { /*ConfigForm.ShowDialog();*/}
        #endregion

        #region Basic Variables
        private static LocalPlayer Me { get { return Styx.StyxWoW.Me; } }
        private static WoWUnit MyTarget { get { return Me.GotTarget ? Me.CurrentTarget : null; } }

        private static bool WeakAura_allowed = false;
        private static WoWUnit _lastTarget = null;
        private static Stopwatch timer = new Stopwatch();
        private static Stopwatch timerCombat = new Stopwatch();

        #endregion

        #region Basic Settings && Behaviors
        public override bool NeedPreCombatBuffs { get { return true; } }
        public override Composite CombatBehavior { get { return new ActionRunCoroutine(ctx => CombatCoroutine()); } }
        public override Composite PreCombatBuffBehavior { get { return new ActionRunCoroutine(ctx => PreCombatCoroutine()); } }
        #endregion 


        #region Initialize & Shutdown
        public override void Initialize()
        {
            Utilities.log("Initialized");
            BotEvents.OnBotStarted += this.BotEvents_OnBotStarted;
            BotEvents.OnBotStopped += this.BotEventsOnOnBotStopped;
            TalentManager.Init();

            try
            {
                TalentManager.Update();
            }
            catch (Exception e)
            {
                StopBot(e.ToString());
            }
            
        }

        static int countRentrancyStopBot = 0;
        private static void StopBot(string reason)
        {
            if (!TreeRoot.IsRunning)
                reason = "Bot Cannot Run: " + reason;
            else
            {
                reason = "Stopping Bot: " + reason;

                if (countRentrancyStopBot == 0)
                {
                    countRentrancyStopBot++;
                    if (TreeRoot.Current != null)
                        TreeRoot.Current.Stop();

                    TreeRoot.Stop();
                }
            }

            Utilities.log(reason);
        }


        static DateTime _nextNoCallMsgAllowed = DateTime.MinValue;
        static DateTime _nextNotInGameMsgAllowed = DateTime.MinValue;
        static DateTime _nextNotInWorldMsgAllowed = DateTime.MinValue;
        static DateTime _nextCombatDisabledMsgAllowed = DateTime.MinValue;
        #region Pulse
        public override void Pulse()
        {

            #region Pulse - check for conditions that we should not Pulse during

            if (!StyxWoW.IsInGame)
            {
                if (DateTime.Now > _nextNotInGameMsgAllowed)
                {
                    Utilities.log("info: not in game");
                    _nextNotInGameMsgAllowed = DateTime.Now.AddSeconds(30);
                }
                return;
            }
            _nextNotInGameMsgAllowed = DateTime.MinValue;

            if (!StyxWoW.IsInWorld)
            {
                if (DateTime.Now > _nextNotInWorldMsgAllowed)
                {
                    Utilities.log("info: not in world");
                    _nextNotInWorldMsgAllowed = DateTime.Now.AddSeconds(30);
                }
                return;
            }
            _nextNotInWorldMsgAllowed = DateTime.MinValue;

            // output messages about pulldistance and behaviorflag changes here
           // MonitorPullDistance();
           // MonitorBehaviorFlags();

            // now if combat disabled, bail out 
            if (Bots.Grind.BehaviorFlags.Combat != (Bots.Grind.LevelBot.BehaviorFlags & Bots.Grind.BehaviorFlags.Combat))
                return;

            _nextCombatDisabledMsgAllowed = DateTime.MinValue;

            #endregion

            if (TalentManager.Pulse())
                return;
        }
        #endregion

        public override void ShutDown()
        {          
            BotEvents.OnBotStarted -= this.BotEvents_OnBotStarted;
            BotEvents.OnBotStopped -= this.BotEventsOnOnBotStopped;
        }
        #endregion

        #region Events
        private void BotEvents_OnBotStarted(EventArgs args)
        {
            Character.getGlyphs();
            Character.getEnergyRegen();

            Utilities.log("Shred glyph: {0}", Character.Glyphs[Spells.Shred].ToString());
        }
        private void BotEventsOnOnBotStopped(EventArgs args)
        {

        }
        #endregion


        #region PreCombat
        private static async Task<bool> PreCombatCoroutine()
        {
            global::KittyDru.Rotation.Rotation.doSet(global::KittyDru.Rotation.Rotation.RotationType.NULL);

            //Utilities.log("Precombat Buffs");
            if (Utilities.BusyCheck()) return true;

            if (await Spells.doBuffs()) return true;


            return false;
        }
        #endregion

        #region Combat
        private static async Task<bool> CombatCoroutine()
        {
            if (!Me.IsAlive) return false;
            //ObjectManager.Update();

            if (Utilities.SafeFacingBehind()) return true;
            else  if (Utilities.SafeFacing()) return true;

            if (await NeedMove()) return true;

            if (await Spells.doBuffs()) return true;

            if (await PVE.RotationsChooser()) return true;
            
            return false;
        }

        private static async Task<bool> NeedMove()
        {
            if((Me.GotTarget && Me.CurrentTarget.Location.Distance2D(Me.Location) < 15) || !Me.IsActuallyInCombat) return false;

            if (Me.GotTarget && Me.IsMoving && Spells.SpellCDLeft(Spells.Dash) < 1)
            {
                return await Spells.SpellCast(Spells.Dash);
            }
            else if (!Me.GotTarget || (Me.GotTarget && Me.CurrentTarget.IsValid && Me.CurrentTarget.IsAlive && Unit.ValidUnit(Me.CurrentTarget) && Me.CurrentTarget.Location.Distance2D(Me.Location) < 25))
            {
                Utilities.SafeFacingBehind();
                return await Spells.SpellCast(Spells.WildCharge);
            }
            return false;
        }
        #endregion

    }
}
